import cgi
import os
import re
import urllib
import urlparse
import mimetypes
#import xpath
from xml.dom import minidom

from xml.sax import saxutils
from django.utils import simplejson
from google.appengine.api import urlfetch
from google.appengine.api.urlfetch import DownloadError
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class FFOPML(webapp.RequestHandler):
  @staticmethod
  def getRequestParams(requestQueryString, paramsList):
    requestQueryString = "&" + requestQueryString
    paramIndexes = [(param, requestQueryString.find('&' + param + '=')) for param in paramsList]
    paramIndexes = sorted(filter(lambda x: x[1]!=-1, paramIndexes),key=lambda x:x[1])
    paramIndexes = [(paramIndexes[i][0], paramIndexes[i][1] + len(paramIndexes[i][0]) + 2, len(requestQueryString) if (i == (len(paramIndexes)-1)) else paramIndexes[i+1][1])
                    for i in range(len(paramIndexes))]
    return dict((param[0], urllib.unquote(requestQueryString[param[1]:param[2]])) for param in paramIndexes)

  @staticmethod
  def fetchContent(contentUrl, maxRetryCount=2, maxTimeout=10):
    contentUrl = contentUrl.replace(" ", "%20")
    for i in range(maxRetryCount):
      try:
        fetchResult = urlfetch.fetch(contentUrl, deadline=maxTimeout)
        break
      except DownloadError:
        fetchResult = None
    if not(fetchResult) or fetchResult.status_code != 200:
      return None
    else:
      return fetchResult.content
 
  @staticmethod
  def fetchContentDOM(contentUrl):
    contentString = FFOPML.fetchContent(contentUrl)
    return minidom.parseString(contentString)
   
  @staticmethod
  def fetchContentJSON(contentUrl):
    contentString = FFOPML.fetchContent(contentUrl)
    return simplejson.loads(contentString)
   
  @staticmethod
  def isOPML(opmlDom):
    rootTagName = opmlDom.documentElement.localName
    return rootTagName.lower() == "opml"
 
  def parseOPML(self, opmlUrl):
    contentString = FFOPML.fetchContent(opmlUrl)
    opmlDom = minidom.parseString(contentString)

    if not(FFOPML.isOPML(opmlDom)):
      return None

    opmlItems = xpath.find('//*[local-name() = "outline" and @xmlUrl]', opmlDom.documentElement)

    opmlUrls = []
    for opmlItem in opmlItems:
      itemType = opmlItem.getAttribute('type')
      itemUrl = opmlItem.getAttribute('xmlUrl')
      itemTitle = opmlItem.getAttribute('title')
      opmlUrls += [{'title' : itemTitle, 'url' : itemUrl, 'type' : itemType }]
   
    return opmlUrls
 
  # FF mechanized script in ruby:
  # http://github.com/knu/ruby-friendfeed/blob/01815b113d4b0f06602ac390b4769d102bfd53af/lib/friendfeed/unofficial.rb
 
  '''
    # Creates a new feed of a given (unique) +nickname+ and display
    # +name+, and returns a unique ID string on success.  The +type+
    # can be one of "group", "microblog" and "public".  Like other
    # methods in general, an exception is raised on
    # failure. [unofficial]
   def create_group(nickname, name, type = 'group'):
      apiCallUrl = 'http://friendfeed.com/a/createfeed?nickname=%s&name=%s&type=%s'
      post(ROOT_URI + '/a/createfeed', 'nickname' => nickname, 'name' => name, 'type' => type).xpath("(//a[@class='l_feedinvite'])[1]/@sid").to_s
      return
   
        # Adds a feed to the authenticated user or a group specified by a
    # unique ID.  Specify 'isstatus' => 'on' to display entries as
    # messages (no link), and 'importcomment' => 'on' to include entry
    # description as a comment. [unofficial]
    def add_service(id, service, options = nil)
      params = {
        'stream' => id,
        'service' => service,
      }
      params.update(options) if options
      post(ROOT_URI + '/a/configureservice', params)
    end
 
        # Adds a feed to the authenticated user or a group specified by a
    # unique ID.  Specify 'isstatus' => 'on' to display entries as
    # messages (no link), and 'importcomment' => 'on' to include entry
    # description as a comment. [unofficial]
    def add_feed(id, url, options = nil)
      params = { 'url' => url }
      params.update(options) if options
      add_service(id, 'feed', options)
    end
  '''
 
  # python mechanize library and twill extension:
  # http://wwwsearch.sourceforge.net/mechanize/
  # http://twill.idyll.org/python-api.html
 
  def importOPML(self, opml, group, comment, message, username, password, remotekey):
    # get opml
    # check if room exists
    # if room does not exist - create
    # add feeds as custom rss feeds with options
   
    # icons:
    # http://opml.us/images/opml-icon.jpg
    # http://i.friendfeed.com/37829cd45442053ec5ec3462121dc79845fff8c3
    # http://practicumpioneers.files.wordpress.com/2009/02/friendfeed.jpg
    pass
 
  def get(self):
    requestParams = FFOPML.getRequestParams(self.request.query_string, ['opmlUrl'])
    opmlItems = self.parseOPML(requestParams['opmlUrl'])
   
    #feedUrl = self.filterFeedUrl(requestParams['inputFeedUrl'])
    # check if ff room/imaginary friend exists
    # for each url - add url to room/friend as custom rss/atom service
    #http://friendfeed.com/api/room/friendfeed-news/profile
    #http://friendfeed.com/api/room/friendfeed-news/subscribe
   
    self.response.out.write(str(opmlItems))
    return

application = webapp.WSGIApplication([('/ffopml.*', FFOPML)], debug=True)

def main():
  run_wsgi_app(application)

if __name__ == "__main__":
  main()

